package com.ruyuan.seckill.service.impl;


import com.alibaba.fastjson.JSON;
import com.ruyuan.seckill.cache.Cache;
import com.ruyuan.seckill.domain.enums.CachePrefix;
import com.ruyuan.seckill.domain.vo.CacheGoods;
import com.ruyuan.seckill.domain.vo.GoodsSkuVO;
import com.ruyuan.seckill.service.GoodsQueryManager;
import com.ruyuan.seckill.utils.JsonUtil;
import com.ruyuan.seckill.utils.StockCacheKeyUtil;
import com.ruyuan.seckill.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 商品业务类
 */
@Service
@Slf4j
public class GoodsQueryManagerImpl implements GoodsQueryManager {
    @Autowired
    private Cache cache;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 缓存中查询商品的信息
     *
     * @param goodsId
     * @return
     */
    @Override
    public CacheGoods getFromCache(Integer goodsId) {
        String goodsStr =  stringRedisTemplate.opsForValue().get(CachePrefix.CACHE_GOODS.getPrefix() + goodsId);
        CacheGoods cacheGoods = JSON.parseObject(goodsStr, CacheGoods.class);
        log.debug("由缓存中读出商品：");
        log.debug(JsonUtil.objectToJson(cacheGoods));

        //填充库存数据
        fillStock(cacheGoods);


        return cacheGoods;
    }

    /**
     * 为商品填充库存信息<br/>
     * 库存的信息存储在单独的缓存key中<br/>
     * 由缓存中读取出所有sku的库存，并分别为goods.skuList中的sku设置库存，以保证库存的时时正确性<br/>
     * 同时还会将所有的sku库存累加设置为商品的库存
     *
     * @param goods
     */
    private void fillStock(CacheGoods goods) {

        List<GoodsSkuVO> skuList = goods.getSkuList();

        //由缓存中获取sku的可用库存和实际库存
        //此操作为批量操作，因为是高频操作，要尽量减少和redis的交互次数
        List keys = createKeys(skuList);

        //将商品的可用库存和实际库存一起读
        keys.add(StockCacheKeyUtil.goodsEnableKey(goods.getGoodsId()));
        keys.add(StockCacheKeyUtil.goodsActualKey(goods.getGoodsId()));

        List<String> quantityList = stringRedisTemplate.opsForValue().multiGet(keys);
        if (quantityList.get(0)==null) {
            Map map = new HashMap();
            for (Object key : keys) {
                map.put(key, goods.getQuantity().toString());
            }
            stringRedisTemplate.opsForValue().multiSet(map);
            quantityList = stringRedisTemplate.opsForValue().multiGet(keys);
        }

        int enableTotal = 0;
        int actualTotal = 0;

        int i = 0;
        for (GoodsSkuVO skuVO : skuList) {

            //第一个是可用库存
            Integer enable = StringUtil.toInt(quantityList.get(i), null);

            i++;
            //第二个是真实库存
            Integer actual = StringUtil.toInt(quantityList.get(i), null);

            // //缓存被击穿，由数据库中读取
            // if (enable == null || actual == null) {
            //     Map<String, Integer> map = goodsQuantityManager.fillCacheFromDB(skuVO.getSkuId());
            //     enable = map.get("enable_quantity");
            //     actual = map.get("quantity");
            //
            //     //重置缓存中的库存
            //     stringRedisTemplate.opsForValue().set(StockCacheKeyUtil.skuEnableKey(skuVO.getSkuId()), "" + enable);
            //     stringRedisTemplate.opsForValue().set(StockCacheKeyUtil.skuActualKey(skuVO.getSkuId()), "" + actual);
            // }


            skuVO.setEnableQuantity(enable);
            skuVO.setQuantity(actual);

            if (enable == null) {
                enable = 0;
            }

            if (actual == null) {
                actual = 0;
            }
            //累计商品的库存
            enableTotal += enable;
            actualTotal += actual;

            i++;
        }


        //设置商品的库存
        goods.setEnableQuantity(enableTotal);
        goods.setQuantity(actualTotal);


        //读取缓存中商品的库存，看是否被击穿了
        //第一个是可用库存
        Integer goodsEnable = StringUtil.toInt(quantityList.get(i), null);

        i++;
        //第二个是真实库存
        Integer goodsActual = StringUtil.toInt(quantityList.get(i), null);

        //商品的库存被击穿了
        if (goodsEnable == null || goodsActual == null) {
            //重置缓存中的库存
            stringRedisTemplate.opsForValue().set(StockCacheKeyUtil.goodsEnableKey(goods.getGoodsId()), "" + enableTotal);
            stringRedisTemplate.opsForValue().set(StockCacheKeyUtil.goodsActualKey(goods.getGoodsId()), "" + actualTotal);
        }


    }

    /**
     * 生成批量获取sku库存的keys
     *
     * @param goodsList
     * @return
     */
    private List createKeys(List<GoodsSkuVO> goodsList) {
        List keys = new ArrayList();
        for (GoodsSkuVO goodsSkuVO : goodsList) {

            keys.add(StockCacheKeyUtil.skuEnableKey(goodsSkuVO.getSkuId()));
            keys.add(StockCacheKeyUtil.skuActualKey(goodsSkuVO.getSkuId()));
        }
        return keys;
    }
}
